/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

import { AttachmentBody } from './AttachmentBody'
import { RecipientType } from './RecipientType';
import { Folder } from './Folder';
import { EmlFormat } from '../emlformat/EmlFormat';
import Result from '../emlformat/Result';
import { Util } from '../Util';
import { Flag } from './Flag';
import { MimeMultipart } from './MimeMultipart';
import { MailLogger } from '../MailLogger';

/**
 * 邮件实体类以及邮件相关操作
 */
export class Message {
    private date: string
    private subject: string
    private froms: string[]
    private to: string[]
    private Cc: string[]
    private Bcc: string[]
    private text: string = ""
    private files: Array<AttachmentBody>;
    private inlineFiles: Array<AttachmentBody>;
    private mimeVersion: string;
    private contentType: string;
    private html: string = ""
    private lineCount: number
    private size: number
    private expunged: boolean
    private msgnum: number
    private replayTo: string[]
    private folder: Folder
    public result: Result = {}
    private textCharset = ""
    private textEncoding = ""
    private textSize = 0
    private htmlCharset = ""
    private htmlEncoding = ""
    private htmlSize = 0
    private textIndex = "1"
    private htmlIndex = "2"
    private nowIndex = "1"

    constructor(folder?: Folder, msgnum?: number) {
        this.folder = folder
        this.msgnum = msgnum
    }

    /**
     * 获取当前邮件所属邮箱
     */
    public getFolder(): Folder {
        return this.folder;
    }

    public setContentType(contentType: string) {
        return this.contentType = contentType
    }

    public getContentType() {
        return this.contentType
    }

    /**
     * 设置flag
     */
    public setFlags(flags: Flag[], isAdd: boolean, callback) {
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().setFlag(this.msgnum, flags, isAdd, (err) => {
                callback(err)
            })
        }
    }

    /**
     * 同步获取 flag
     */
    public syncGetFlags(): Promise<String[]> {
        return new Promise((resolve, reject) => {
            this.getFlags((success, result) => {
                if (success) {
                    resolve(result)
                } else {
                    reject(result)
                }
            })
        })
    }

    /**
     * 获取 flag
     */
    public getFlags(callback) {
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().getFlags(this.msgnum, (success, result) => {
                callback(success, result)
            })
        }
    }

    /**
     * 设置邮件发送时间
     */
    public setSentDate(date: string) {
        this.date = date
    }

    /**
     * 获取邮件发送时间
     */
    public getSentDate(): string {
        if (!!this.date) {
            return this.date
        }

        if (!!this.result && this.result.hasOwnProperty('headers')) {
            return this.result.headers.Date
        }
    }

    /**
     * 获取邮件行数
     */
    public getLineCount(): number {
        return this.lineCount
    }

    /**
     * 获取邮件大小
     */
    public getSize(callback) {
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().getSize(this.msgnum, (success, result) => {
                callback(success, result)
            })
        } else {
            callback(false, "store is undefined")
        }
    }

    /**
     * 同步获取邮件完整内容
     */
    public syncGetContent(): Promise<MimeMultipart | Message> {
        return new Promise((resolve, reject) => {
            this.getContent((success, result) => {
                if (success) {
                    resolve(result)
                } else {
                    reject(result)
                }
            })
        })
    }

    /**
     * 获取邮件完整内容
     */
    public getContent(callback) {
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().getContent(this.msgnum, (success, result) => {
                if (success) {
                    if (result == "") {
                        callback(false, "mail content is empty")
                        return
                    }

                    if (this.folder.getProtocol() == "imap") {
                        let mimeMultipart = this.parserBodyStructure(result)
                        if (!mimeMultipart) {
                            callback(false, "mail content parse fail")
                        } else {
                            callback(true, mimeMultipart)
                        }
                        return
                    }

                    if (this.folder.getProtocol() == "pop3") {
                        EmlFormat.parseString(result, (success, result) => {
                            if (success) {
                                this.result.body = result.body
                                Util.parserContent(result, this)
                                callback(true, this)
                            } else {
                                callback(false, result)
                            }
                        });
                    }
                } else {
                    callback(false, "get content fail")
                }
            })
        } else {
            callback(false, "store is undefined")
        }
    }

    /**
     * 同步获取邮件Header以及正文的前几行
     */
    public syncGetLineContent(lineCount): Promise<Message> {
        return new Promise((resolve, reject) => {
            this.getLineContent(lineCount, (success, result) => {
                if (success) {
                    resolve(result)
                } else {
                    reject(result)
                }
            })
        })
    }

    /**
     * 获取邮件Header以及正文的前几行
     */
    public getLineContent(lineCount, callback) {
        if (this.folder.getProtocol() != "pop3") {
            callback(false, this.folder.getProtocol() + " not support")
            return
        }
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().getLineText(this.msgnum, lineCount, (success, result) => {
                if (success) {
                    if (result == "") {
                        callback(false, "mail content is empty")
                        return
                    }

                    EmlFormat.parseString(result, (success, result) => {
                        if (success) {
                            this.result.body = result.body
                            Util.parserContent(result, this)
                            callback(true, this)
                        } else {
                            callback(false, result)
                        }
                    });
                } else {
                    callback(false, "get content fail")
                }
            })
        } else {
            callback(false, "store is undefined")
        }
    }

    /**
     * 设置邮件大小
     */
    public setSize(size: number) {
        this.size = size
    }

    /**
     * 邮件是否已经删除
     */
    public isExpunged(): boolean {
        return this.expunged
    }

    /**
     * 设置是否删除邮件
     */
    public setExpunged(expunged: boolean) {
        return this.expunged = expunged
    }

    /**
     * 获取邮件编号
     */
    public getMessageNumber(): number {
        return this.msgnum
    }

    /**
     * 设置邮件编号
     */
    public setMessageNumber(num: number) {
        this.msgnum = num
    }

    /**
     * 获取接收日期
     */
    public getReceivedDate(): string {
        if (!!this.date) {
            return this.date
        }

        if (!!this.result && this.result.hasOwnProperty('headers')) {
            return this.result.headers.Date
        }
    }

    /**
     * 设置主题
     */
    public setSubject(subject: string) {
        this.subject = subject
    }

    /**
     * 获取主题
     */
    public getSubject(): string {
        if (!!this.subject) {
            return this.subject
        }

        if (!!this.result.headers) {
            if (!!!this.result.headers.Subject) {
                return undefined
            }
            let subject = this.result.headers.Subject
            if (subject.startsWith("=?") && subject.endsWith("?=")) {
                let arr = subject.split("?")
                if (arr[1].includes("gb") || arr[1].includes("GBK")) {
                    subject = Util.strAnsi2Unicode(Util.decodeBase64(arr[3]).output); //解密
                } else if (arr[1].includes("utf") || arr[1].includes("UTF")) {
                    subject = Util.decode(arr[3])
                }
            }
            return subject
        }
        return undefined
    }

    /**
     *  设置发件人
     */
    public setFrom(from: string[]) {
        this.froms = from
    }

    /**
     *  获取发件人
     */
    public getFrom(): string[] {
        if (!!this.froms) {
            return this.froms
        } else {
            if (!!this.result && this.result.hasOwnProperty('headers') && this.result.headers.hasOwnProperty('From')) {
                this.froms = this.result.headers.From.split(', ')
                return this.froms
            }
        }
    }

    /**
     *  获取回复人
     */
    public getReplyTo(): string[] {
        if (!!this.replayTo) {
            return this.replayTo
        }

        if (!!this.result && this.result.hasOwnProperty('headers') && this.result.headers.hasOwnProperty('Reply-To')) {
            this.replayTo = this.result.headers['Reply-To'].split(', ')
            return this.replayTo
        }
    }

    /**
     *  设置回复人
     */
    public setReplyTo(address: string[]) {
        this.replayTo = address
    }

    /**
     *  根据收件人类型设置收件人
     */
    public setRecipients(addressType: RecipientType, addresses: string[]) {
        switch (addressType) {
            case RecipientType.TO:
                this.to = addresses
                break;
            case RecipientType.CC:
                this.Cc = addresses
                break;
            case RecipientType.BCC:
                this.Bcc = addresses
                break;
            default:
                break;
        }
    }

    /**
     *  根据收件人类型追加收件人
     */
    public addRecipients(addressType: RecipientType, addresses: string[]) {
        switch (addressType) {
            case RecipientType.TO:
                if (!!this.to) {
                    this.to = this.to.concat(addresses)
                }
                break;
            case RecipientType.CC:
                if (!!this.Cc) {
                    this.Cc = this.Cc.concat(addresses)
                }
                break;
            case RecipientType.BCC:
                if (!!this.Cc) {
                    this.Bcc = this.Bcc.concat(addresses)
                }
                break;
            default:
                break;
        }
    }

    /**
     *  通过收件人类型获取收件人
     */
    public getRecipients(addressType: RecipientType): string[] {
        switch (addressType) {
            case RecipientType.TO:
                if (!!this.to) {
                    return this.to
                }

                if (!!this.result && this.result.hasOwnProperty('headers') && this.result.headers.hasOwnProperty('To')) {
                    this.to = this.result.headers.To.split(', ')
                    return this.to
                }
                break;
            case RecipientType.CC:
                if (!!this.Cc) {
                    return this.Cc
                }

                if (!!this.result && this.result.hasOwnProperty('headers') && this.result.headers.hasOwnProperty('Cc')) {
                    this.Cc = this.result.headers.Cc.split(', ')
                    return this.Cc
                }
                break;
            case RecipientType.BCC:
                if (!!this.Bcc) {
                    return this.Bcc
                }

                if (!!this.result && this.result.hasOwnProperty('headers') && this.result.headers.hasOwnProperty('Bcc')) {
                    this.Bcc = this.result.headers.Bcc.split(', ')
                    return this.Bcc
                }
                break;
            default:
                break;
        }
    }

    /**
     * 获取所有收件人
     */
    public getAllRecipients(): string[] {
        return this.to.concat(this.Cc).concat(this.Bcc)
    }

    /**
     * 设置邮件文本内容
     */
    public setText(text: string) {
        this.text = text
    }

    /**
     * 获取邮件文本内容
     */
    public getText() {
        return this.text
    }

    /**
     * 添加附件
     */
    public addFiles(file: AttachmentBody) {
        if (!!!this.files) {
            this.files = new Array<AttachmentBody>()
        }
        if (!!file) {
            this.files.push(file)
        }
    }

    /**
     * 获取所有附件
     */
    public getFiles() {
        return this.files
    }

    /**
     * 添加内联附件
     */
    public addInlineFiles(inlineFile: AttachmentBody) {
        if (!!!this.inlineFiles) {
            this.inlineFiles = new Array<AttachmentBody>()
        }
        if (!!inlineFile) {
            this.inlineFiles.push(inlineFile)
        }
    }

    /**
     * 获取所有内联附件
     */
    public getInlineFiles() {
        return this.inlineFiles
    }

    /**
     * 设置邮件HTML
     */
    public setHtml(html: string) {
        this.html = html
    }

    /**
     * 获取邮件HTML
     */
    public getHtml() {
        return this.html
    }

    /**
     * 设置邮件MIMEVersion
     */
    public setMIMEVersion(mIMEVersion: string) {
        this.mimeVersion = mIMEVersion
    }

    /**
     *  获取邮件MIMEVersion
     */
    public getMIMEVersion(callback) {
        if (!!this.mimeVersion) {
            callback(true, this.mimeVersion)
            return
        }

        this.getHeader('MIME-Version', (success, result) => {
            if (success) {
                this.mimeVersion = result
                callback(success, result)
            } else {
                callback(false, result)
            }
        })
    }

    /**
     *  通过header名称获取header
     */
    public getHeader(headerName: string, callback) {
        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().getHeader(this.msgnum, headerName, (success, result) => {
                callback(success, result)
            })
        } else {
            callback(false, "store is undefined")
        }
    }

    /**
     *  获取所有header
     */
    public getAllHeaders(callback) {
        if (!!this.result.headers) {
            callback(true, this.result.headers)
            return
        }

        if (!!this.folder && !!this.folder.getStore()) {
            this.folder.getStore().geAllHeader(this.msgnum, (success, result) => {
                if (success) {
                    EmlFormat.parseHeaders(result, (success, result) => {
                        this.result.headers = result.headers
                        if (result.hasOwnProperty('headers')) {
                            if (this.result.headers.hasOwnProperty("From")) {
                                let froms = result.headers.From
                                this.setFrom(Util.matchRecipient(froms))
                            }

                            if (this.result.headers.hasOwnProperty("Subject")) {
                                let subject = result.headers.Subject
                                this.setSubject(Util.parseSubject(subject))
                            }

                            if (this.result.headers.hasOwnProperty('To')) {
                                let to = result.headers.To
                                this.setRecipients(RecipientType.TO, Util.matchRecipient(to))
                            }

                            if (result.headers.hasOwnProperty("SendTo")) {
                                let to = result.headers.SendTo
                                this.setRecipients(RecipientType.TO, Util.matchRecipient(to))
                            }

                            if (this.result.headers.hasOwnProperty('Cc')) {
                                let cc = result.headers.Cc
                                this.setRecipients(RecipientType.CC, Util.matchRecipient(cc))
                            }

                            if (this.result.headers.hasOwnProperty('Bcc')) {
                                let bcc = result.headers.Bcc
                                this.setRecipients(RecipientType.BCC, Util.matchRecipient(bcc))
                            }

                            if (this.result.headers.hasOwnProperty('Date')) {
                                this.setSentDate(result.headers.Date)
                            }

                            if (this.result.headers.hasOwnProperty('MIME-Version')) {
                                this.setMIMEVersion(result.headers['MIME-Version'])
                            }

                            if (this.result.headers.hasOwnProperty('Reply-To')) {
                                this.setReplyTo(result.headers['Reply-To'].split(', '))
                            }

                            if (this.result.headers.hasOwnProperty('Content-Type')) {
                                this.setContentType(result.headers['Content-Type'].split(', '))
                            }
                        }
                        callback(success, this)
                    });
                } else {
                    callback(false, result)
                }
            })
        } else {
            callback(false, "store is undefined")
        }
    }

    private parserBodyStructure(bodyStr: string): MimeMultipart {
        let partCount = 0

        let regex = /{(\d+)}\r\n/; // 匹配 {数字} 的正则表达式
        if (regex.test(bodyStr)) {
            let match;
            while (match = regex.exec(bodyStr)) {
                let strNum = parseInt(match[1]); // 将匹配到的数字字符串转换为整数
                let index = match.index + match[0].length; // 计算右括号 } 的索引位置
                let subStr = bodyStr.substr(index, strNum);
                let result = Util.decodeMimeStr(subStr);
                bodyStr = bodyStr.substring(0, match.index) + "\"" + result + "\"" + bodyStr.substring(index + strNum); // 将子字符串替换为新字符串
            }
        }
        let body = bodyStr.replace(/\(/g, '[')
        body = body.replace(/\)/g, ']')
        body = body.replace(/\]\[/g, '],[')
        body = body.replace(/NIL/g, null)
        body = body.replace(/ /g, ',')

        let bodyArr
        try {
            bodyArr = JSON.parse(body)
        } catch (e) {
            MailLogger.error('ohos_mail-- parserBodyStructure bodyArr fail:' + e)
            return null
        }
        partCount = bodyArr.length - 5
        if (bodyArr[0] instanceof Array) {
            for (let index = 0; index < bodyArr.length; index++) {
                let bodyIndexPart = bodyArr[index]
                this.nowIndex = (index + 1) + ""
                this.buildWholeBody(bodyIndexPart)
            }
        } else {
            this.buildAttachment(bodyArr)
        }

        let mimeMultipart = new MimeMultipart(this.msgnum, this.folder.getStore())
        mimeMultipart.setCount(partCount)
        mimeMultipart.setTextCharset(this.textCharset)
        mimeMultipart.setTextEncoding(this.textEncoding)
        mimeMultipart.setTextSize(this.textSize)
        mimeMultipart.setTextIndex(this.textIndex)
        mimeMultipart.setHtmlCharset(this.htmlCharset)
        mimeMultipart.setHtmlEncoding(this.htmlEncoding)
        mimeMultipart.setHtmlSize(this.htmlSize)
        mimeMultipart.setHtmlIndex(this.htmlIndex)
        mimeMultipart.setAttachmentFiles(this.getFiles())
        mimeMultipart.setInlineAttachmentFiles(this.getInlineFiles())

        let bodyStructure = " textCharset " + this.textCharset
        + " textEncoding " + this.textEncoding
        + " textSize " + this.textSize
        + " htmlCharset " + this.htmlCharset
        + " htmlEncoding " + this.htmlEncoding
        + " htmlSize " + this.htmlSize

        let attachFiles = this.getFiles()
        if (!!attachFiles && attachFiles.length > 0) {
            for (let i = 0; i < attachFiles.length; i++) {
                let file = attachFiles[i]
                bodyStructure += " filename " + file.getFileName()
                + " fileEncoding " + file.getEncoding()
                + " fileMime " + file.getMimeType()
                + " fileSize " + file.getSize()
            }
        }

        let inlineFiles = this.getInlineFiles()
        if (!!inlineFiles && inlineFiles.length > 0) {
            for (let i = 0; i < inlineFiles.length; i++) {
                let inlineFile = inlineFiles[i]
                bodyStructure += " inline filename " + inlineFile.getFileName()
                + " inline fileEncoding " + inlineFile.getEncoding()
                + " inline fileMime " + inlineFile.getMimeType()
                + " inline fileSize " + inlineFile.getSize()
            }
        }
        MailLogger.info("ohos_mail bodyStructure  " + bodyStructure)
        return mimeMultipart
    }

    private buildWholeBody(bodyIndexPart) {
        if (bodyIndexPart instanceof Array) {
            let bodyIndexPartHead = bodyIndexPart[0]
            if (bodyIndexPartHead instanceof Array) {
                for (let i = 0; i < bodyIndexPart.length; i++) {
                    let bodySecond = bodyIndexPart[i]
                    if (!!bodySecond && bodySecond.length > 10) {
                        this.buildContentBody(bodySecond, i, false)
                        let sign = this.nowIndex.lastIndexOf(".");
                        if (sign !== -1) {
                            this.nowIndex = this.nowIndex.substring(0, sign); // 取出点号前面的内容
                        }
                    }else if(!!bodySecond && bodySecond instanceof Array){
                        this.nowIndex = this.nowIndex + "." + (i + 1);
                        this.buildAttachment(bodySecond);
                        let sign = this.nowIndex.lastIndexOf(".");
                        if (sign !== -1) {
                            this.nowIndex = this.nowIndex.substring(0, sign); // 取出点号前面的内容
                        }
                    }
                }
            } else {
                this.buildAttachment(bodyIndexPart)
            }
        }
    }

    private buildContentBody(bodyArr, index, isFromBuildAttachment:boolean) {
        if (!!bodyArr && bodyArr.length > 6) {
            if(!isFromBuildAttachment){
                index = index + 1;
                this.nowIndex += "." + index
            }
            if (bodyArr[1] instanceof Array) {
                this.buildWholeBody(bodyArr)
            } else if(typeof bodyArr[1] === "string"){
                let type = bodyArr[1].toUpperCase()
                if (type == "PLAIN") {
                    this.textCharset = bodyArr[2][1]
                    this.textEncoding = bodyArr[5]
                    this.textSize = bodyArr[6]
                    this.textIndex = this.nowIndex
                }else if (type == "HTML") {
                    this.htmlCharset = bodyArr[2][1]
                    this.htmlEncoding = bodyArr[5]
                    this.htmlSize = bodyArr[6]
                    this.htmlIndex = this.nowIndex
                }
            }
        }
    }

    private buildAttachment(bodyArr) {
        let isAttachment: boolean = false
        let fileName: string
        let attachmentType: string
        if (bodyArr[0] == "Message") {
            fileName = bodyArr[4]
            isAttachment = true
        } else {
            for (let i = 0; i < bodyArr.length; i++) {
                if (bodyArr[i] instanceof Array && typeof bodyArr[i][0] === "string") {
                    let attachment = bodyArr[i][0].toUpperCase()
                    if (attachment == "ATTACHMENT" || attachment == "INLINE") {
                        if (!!bodyArr[i][1]) {
                            fileName = bodyArr[i][1][1]
                            isAttachment = true
                            attachmentType = attachment
                        }
                    }
                }
            }
        }

        if (isAttachment) {
            let file = new AttachmentBody("", Util.matchAndDecode(fileName))
            file.setEncoding(bodyArr[5])
            file.setMimeType(bodyArr[0] + "/" + bodyArr[1])
            file.setSize(bodyArr[6])
            if (bodyArr[2] instanceof Array) {
                if (typeof bodyArr[2][0] === "string" && bodyArr[2][0].toUpperCase() == "CHARSET") {
                    file.setCharSet(bodyArr[2][1])
                }
            }
            file.setIndex(this.nowIndex)
            file.setCid(bodyArr[3])
            if(attachmentType == "ATTACHMENT"){
                this.addFiles(file)
            }else if(attachmentType == "INLINE"){
                this.addInlineFiles(file)
            }
        } else {
            this.buildContentBody(bodyArr,this.nowIndex, true)
        }
    }
}